package com.xiaomaoguai.fcp.kepler.utils;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.LineIterator;
import org.apache.commons.io.filefilter.DirectoryFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 取缔FileTool ,文件操作类 加解密
 *
 * @author WeiHui
 * @date 2019/1/23
 */
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class KeplerFileUtils {

	/**
	 * 系统临时目录
	 */
	public static final String SYS_TEMP_PATH = FileUtils.getUserDirectoryPath();

	/**
	 * 项目临时目录
	 */
	public static final String LOCAL_TEMP_PATH = SystemUtils.USER_DIR;

	/**
	 * 文件路径拆解
	 */
	public static final Splitter SPLITTER = Splitter.on(File.separator);

	/**
	 * 文件路径拼接
	 */
	public static final Joiner JOINER = Joiner.on(File.separator);

	public static final String UTF_8 = "UTF-8";

	/**
	 * 创建一个文件
	 *
	 * @param file 文件
	 * @return true-创建成功
	 * @throws java.io.IOException ex
	 */
	public static boolean createFile(File file) {
		boolean flag = false;
		if (!file.exists()) {
			try {
				FileUtils.touch(file);
				flag = true;
			} catch (IOException e) {
				log.error("====>文件创建失败", e);
			}
		}
		return flag;
	}

	public static void deleteFile(File file) {
		if (file.exists()) {
			file.delete();
		}
	}

	/**
	 * 获取临时文件路径
	 *
	 * @param path 多重路径
	 * @return 文件路径
	 */
	public static String getLocalTempPath(String... path) {
		StringBuilder sb = new StringBuilder(LOCAL_TEMP_PATH);
		for (String node : path) {
			sb.append(SPLITTER).append(node);
		}

		return sb.toString();
	}

	/**
	 * 删除历史过期文件.
	 *
	 * @param filePath the file path
	 */
	public static void deleteExpiredFile(String filePath) {
		log.info("deleteExpiredFile, filePath=" + filePath);
		try {
			//如果是文件的话，获取他的目录，再比较每一个文件
			File resolvedFile = new File(filePath);
			if (!resolvedFile.isDirectory()) {
				resolvedFile = resolvedFile.getParentFile();
			}
			Collection<File> deleteFileList = FileUtils.listFiles(resolvedFile,
					new IOFileFilter() {

						@Override
						public boolean accept(File file) {
							return System.currentTimeMillis() - file.lastModified() > 62 * 24 * 60 * 60 * 1000;
						}

						@Override
						public boolean accept(File dir, String name) {
							return System.currentTimeMillis() - dir.lastModified() > 62 * 24 * 60 * 60 * 1000;
						}
					}, DirectoryFileFilter.INSTANCE);

			for (File file : deleteFileList) {
				log.info("Delete file back out of date: {}", file.getName());
				FileUtils.forceDelete(file);
			}
		} catch (Exception e) {
			log.error("deleteExpiredFile error", e);
		}
	}

	public static boolean writeTxtFile(String content, File file) throws Exception {
		RandomAccessFile mm = null;
		boolean flag = false;
		FileOutputStream o;
		try {
			o = new FileOutputStream(file);
			o.write(content.getBytes("UTF-8"));
			o.close();
			flag = true;
		} catch (Exception var9) {
			log.error("====writeTxtFile异常：", var9);
		} finally {
			if (mm != null) {
				((RandomAccessFile) mm).close();
			}
		}
		return flag;
	}

	public static <T> List<T> readTxtFile(String filePath, String encoding, Class<T> clazz) throws IOException {
		String lineTxt;
		InputStreamReader read = null;
		BufferedReader bufferedReader = null;
		List<T> list = new ArrayList<>();
		try {
			File file = new File(filePath);
			if (!file.isFile() || !file.exists()) {
				throw new Exception();
			}
			read = new InputStreamReader(new FileInputStream(file), encoding);
			bufferedReader = new BufferedReader(read);
			while (StringUtils.isNotBlank(lineTxt = bufferedReader.readLine())) {
				if (clazz != null) {
					T object = JSON.parseObject(lineTxt, clazz);
					if (object != null) {
						list.add(object);
					}
				}
			}
			read.close();
		} catch (Exception var11) {
			log.error("=========================文件不存在或者读取文件内容异常：", var11);
		} finally {
			if (read != null) {
				read.close();
			}
			if (bufferedReader != null) {
				bufferedReader.close();
			}
		}
		return list;
	}

	public static LineIterator getLineIterator(String filePath, String encoding) throws IOException {
		LineIterator lineIterator;
		try (FileInputStream fileInputStream = new FileInputStream(filePath)) {
			lineIterator = IOUtils.lineIterator(fileInputStream, encoding);
		} catch (IOException e) {
			log.error("====>文件LineIterator解析失败", e);
			throw e;
		}
		return lineIterator;
	}

	public static List<String> readLinePage(String filename, int lineNum, int readSize,String charset) {
		if(StringUtils.isBlank(charset)){
			charset = UTF_8;
		}
		String line;
		List<String> readList = Lists.newArrayList();
		//构造LineNumberReader实例
		try(LineNumberReader lineNumberReader = new LineNumberReader(new InputStreamReader(new FileInputStream(filename), charset))) {
			int currentTotalNum = lineNum + readSize -1;
			for (int i = 1; i <= currentTotalNum; i++) {
				line = lineNumberReader.readLine();
				if (i >= lineNum && StringUtils.isNotEmpty(line)) {
					readList.add(line);
				}
			}
		} catch (Exception e) {
			log.error("====>文件读取行数解析失败", e);
		}
		return readList;
	}

	public static List<String> readLinePage(String filename, int lineNum, int readSize) {
		return readLinePage(filename,lineNum,readSize, UTF_8);
	}

	public static void removeFile(String filePath, String suffix) throws IOException {
		File file = new File(filePath);
		File[] files = file.listFiles();
		for (int i = 0; i < files.length; ++i) {
			File tmp = files[i];
			if (tmp.toString().endsWith(suffix)) {
				tmp.delete();
			}
		}
	}

	public static void removeFileByName(String filePath, String fileName) throws IOException {
		File file = new File(filePath);
		File[] files = file.listFiles();
		for (File tmp : files) {
			if (tmp.getName().equals(fileName)) {
				tmp.delete();
			}
		}
	}

	public static void downloadFile(String remoteFilePath, String fileName) throws IOException {
		URL urlfile = null;
		HttpURLConnection httpUrl = null;
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		File f = new File(fileName);
		try {
			urlfile = new URL(remoteFilePath);
			httpUrl = (HttpURLConnection) urlfile.openConnection();
			httpUrl.connect();
			bis = new BufferedInputStream(httpUrl.getInputStream());
			bos = new BufferedOutputStream(new FileOutputStream(f));
			int len = 2048;
			byte[] b = new byte[len];
			while ((len = bis.read(b)) != -1) {
				bos.write(b, 0, len);
			}
			bos.flush();
			bis.close();
			httpUrl.disconnect();
		} catch (Exception var17) {
			log.error("====下载远程文件并保存到本地异常：", var17);
		} finally {
			try {
				if (bis != null) {
					bis.close();
				}
				if (bos != null) {
					bos.close();
				}
			} catch (IOException var16) {
				log.error("====下载远程文件并保存到本地，关闭异常：", var16);
			}
		}
	}

	/**
	 * 加密文件
	 *
	 * @param publicKey
	 * @param sourceFilepath
	 * @param localFilePath
	 */
	public static void encryptFile(String publicKey, String sourceFilepath, String localFilePath) {
		FileOutputStream fos = null;
		try {
			byte[] data = Base64Utils.fileToByte(sourceFilepath);
			byte[] resData = RSAUtils.encryptByPublicKey(data, publicKey);
			fos = new FileOutputStream(new File(localFilePath));
			fos.write(resData);
		} catch (Exception e) {
			log.error("文件加密失败,zaFilePath:" + sourceFilepath, e);
			throw new RuntimeException("文件加密失败");
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					log.error("输入文件流关闭失败", e);
				}
			}
		}
	}

	/**
	 * 解密合作方的文件
	 *
	 * @param privateKey
	 * @param sourceFilePath
	 * @param localFilePath
	 */
	public static void decryptFile(String privateKey, String sourceFilePath, String localFilePath) {
		FileOutputStream fos = null;
		try {
			byte[] data = Base64Utils.fileToByte(sourceFilePath);
			byte[] resData = RSAUtils.decryptByPrivateKey(data, privateKey);
			fos = new FileOutputStream(new File(localFilePath));
			fos.write(resData);
		} catch (Exception e) {
			log.error("文件解密失败,filePath:" + sourceFilePath, e);
			throw new RuntimeException("文件解密失败");
		} finally {
			if (fos != null) {
				try {
					fos.close();
				} catch (IOException e) {
					log.error("输入文件流关闭失败", e);
				}
			}
		}
	}

	/**
	 * @param is       the is
	 * @param filePath the file path
	 * @Title: createFileFromInputStream
	 * @Description: 从输出流中创建文件
	 */
	public static void createFileFromInputStream(InputStream is, String filePath) {
		OutputStream outStream = null;
		try {
			byte[] buffer = new byte[is.available()];
			is.read(buffer);

			File targetFile = new File(filePath);
			outStream = new FileOutputStream(targetFile);
			outStream.write(buffer);
		} catch (Exception e) {
			log.error("创建文件失败", e);
		} finally {
			if (outStream != null) {
				try {
					outStream.close();
				} catch (IOException e) {
					log.error("输入流关闭失败", e);
				}
			}
		}
	}

}
